home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / DIRUTIL.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  14KB  |  605 lines

  1. /* dirutil.c - MS-DOS directory reading routines
  2.  *
  3.  * Bdale Garbee, N3EUA, Dave Trulli, NN2Z, and Phil Karn, KA9Q
  4.  * Directory sorting by Mike Chepponis, K3MC
  5.  * adapted for ATARI ST & cleaned up by Rob Janssen, PE1CHL
  6.  * adapted for Lattice C by Walter Doerr, DG2KK
  7.  */
  8.  
  9. #include <stdio.h>
  10. #ifndef LATTICE
  11. #include <ctype.h>        /* DG2KK: force Lattice to use library func. */
  12. #endif
  13. #ifdef LATTICE
  14. #define    S_IJHID        2
  15. #define S_IJSYS        4
  16. #define S_IJDIR        0x10
  17. struct stat {
  18.     char st_mode;            /* that's all we need */
  19. };    
  20. #else
  21. #include <stat.h>
  22. #endif
  23. #ifdef MSDOS
  24. #define  IS_ERROR    == -1        /* error return from MSDOS */
  25. #endif
  26. #ifdef ATARI_ST
  27. #define  IS_ERROR    < 0        /* error return from gemdos */
  28. #include <osbind.h>            /* os interface defines */
  29. #define  bdos        gemdos        /* Atari OS call */
  30. #define  dos(a,b,c,d,e,f) gemdos(a,d,c) /* only valid for FIND func */
  31. #define  st_attr    st_mode     /* what's in a name? */
  32. #define  ST_HIDDEN    S_IJHID     /* Hidden from search */
  33. #define  ST_SYSTEM    S_IJSYS     /* System, hidden from search */
  34. #define  ST_DIRECT    S_IJDIR     /* Directory */
  35. #endif
  36. #include "global.h"
  37.  
  38. #ifndef FALSE
  39. #define FALSE    (0)
  40. #endif
  41.  
  42. #ifndef TRUE
  43. #define TRUE    !(FALSE)
  44. #endif
  45.  
  46. #define REGFILE (ST_HIDDEN|ST_SYSTEM|ST_DIRECT)
  47. #define SET_DTA     0x1a
  48. #define FIND_FIRST    0x4e
  49. #define FIND_NEXT    0x4f
  50.  
  51. struct dirent {
  52.     char rsvd[21];
  53.     char attr;
  54.     short ftime;
  55.     short fdate;
  56.     long fsize;
  57.     char fname[13];
  58. };
  59. #define NULLENT (struct dirent *)0
  60.  
  61. struct dirsort {
  62.     struct dirsort *prev;
  63.     struct dirsort *next;
  64.     struct dirent *direntry;
  65. };
  66. #define NULLSORT (struct dirsort *)0
  67.  
  68. /* Create a directory listing in a temp file and return the resulting file
  69.  * descriptor. If full == 1, give a full listing; else return just a list
  70.  * of names.
  71.  */
  72. FILE *
  73. dir(path,full)
  74. char *path;
  75. int full;
  76. {
  77.     FILE *fp,*tmpfile();
  78.  
  79.     if ((fp = tmpfile()) != NULLFILE)
  80.     {
  81.         getdir(path,full,fp);
  82.         /* This should be rewind(), but Aztec doesn't have it */
  83.         fseek(fp,0L,0);
  84.     }
  85.     return fp;
  86. }
  87.  
  88. /* wildcard filename lookup */
  89. filedir(name,times,ret_str)
  90. char *name;
  91. int times;
  92. char *ret_str;
  93. {
  94.     register char *cp,*cp1;
  95.     static struct dirent sbuf;
  96.  
  97.     bdos(SET_DTA,&sbuf);    /* Set disk transfer address */
  98.  
  99.     /* Find matching file */
  100.     if(dos(times == 0 ? FIND_FIRST:FIND_NEXT,0,REGFILE,name,0,0) IS_ERROR) 
  101.         sbuf.fname[0] = '\0';
  102.  
  103.     /* Copy result to output, forcing to lower case */
  104.     for(cp = ret_str,cp1 = sbuf.fname; cp1 < &sbuf.fname[13] && *cp1 != '\0';)
  105.         *cp++ = (char)tolower(*cp1++);    /* DG2KK: added (char) */
  106.     *cp = '\0';
  107. }
  108.  
  109. /* Change working directory */
  110. docd(argc,argv)
  111. int argc;
  112. char *argv[];
  113. {
  114.     char dirname[128];
  115. #ifdef MSDOS
  116.     char *getcwd();
  117. #endif
  118.  
  119.     if(argc > 1){
  120.         if(chdir(argv[1]) IS_ERROR){
  121.             printf("Can't change directory\n");
  122.             return 1;
  123.         }
  124.     }
  125.  
  126. #ifdef MSDOS
  127.     if(getcwd(dirname,0) != NULLCHAR){
  128.         printf("\\%s\n",dirname);
  129.     }
  130. #endif
  131. #ifdef ATARI_ST
  132.     if (Dgetpath(dirname,0) == 0){
  133.         printf("%c:%s%s\n",(char) Dgetdrv()+'A',
  134.             (*dirname? "" : "\\"),dirname);
  135.     }
  136. #endif
  137.     return 0;
  138. }
  139.  
  140. /* List directory to console. [-/]w option selects "wide" format */
  141. dodir(argc,argv)
  142. int argc;
  143. char *argv[];
  144. {
  145.     char *path;
  146.     int full = 1;
  147.  
  148.     if (argc > 1 &&
  149.         (argv[1][0] == '-' || argv[1][0] == '/') && argv[1][1] == 'w')
  150.     {
  151.         full = -1;
  152.         argv++;
  153.         argc--;
  154.     }
  155.  
  156.     if(argc >= 2){
  157.         path = argv[1];
  158.     } else {
  159.         path = "*.*";
  160.     }
  161.     getdir(path,full,stdout);
  162.     return 0;
  163. }
  164.  
  165. /* do a directory list to the stream 
  166.  * full = 0 -> short form, 1 is long, -1 is multi-column short
  167. */
  168. static
  169. getdir(path,full,file)
  170. char *path;
  171. int full;
  172. FILE *file;
  173. {
  174.     struct dirent sbuf;
  175.     struct stat statbuf;
  176.     char *cp,*cp1;                /* !!!!!!! was: register */
  177.     char dirtmp[20];
  178.     int command = FIND_FIRST;
  179.     int i = 0;
  180.     int cflag = 0;
  181.     int n = 0;
  182.     char line_buf[50];        /* for long dirlist */
  183.     
  184.     struct dirsort *head, *here, *new;
  185.     struct dirent *de;
  186.     void dir_sort(), format_dir(), format_fname(), diskfree(), free_clist();
  187.     int malloc_lost = FALSE;
  188.  
  189.     /* Root directory is a special case */
  190.     if(path == NULLCHAR || *path == '\0' || strcmp(path,"\\") == 0)
  191.         path = "\\*.*";
  192.  
  193.     /* If arg is a directory, append "\*.*" to it.
  194.      * This is tricky, since the "stat" system call actually
  195.      * calls the DOS "find matching file" function. The stat
  196.      * call therefore returns the attributes for the first matching
  197.      * entry in the directory. If the arg already ends in *.*,
  198.      * stat will match the . entry in the directory and indicate
  199.      * that the argument is a valid directory name. Hence the
  200.      * heuristic check for '*' in the file name. Kludge...
  201.      */
  202.     else if(index(path,'*') == NULLCHAR
  203.      && stat(path,&statbuf) != -1
  204.      && (statbuf.st_attr & ST_DIRECT)) {
  205.         if((cp = malloc(strlen(path) + 10)) == NULLCHAR)
  206.             return -1;
  207.         sprintf(cp,"%s%c%s",path,'\\',"*.*");
  208.         path = cp;
  209.         cflag = 1;
  210.     }
  211.     head = NULLSORT;    /* No head of chain yet... */
  212.     for(;;){
  213.         bdos(SET_DTA,&sbuf);    /* Set disk transfer address */
  214.         if(dos(command, 0, REGFILE, path, 0, 0) IS_ERROR)
  215.             break;
  216.  
  217.         command = FIND_NEXT;    /* Got first one already... */
  218.         if(sbuf.fname[0] != '.'){
  219.             /* nuke "." and ".." */
  220.             n++;    /* One more entry */
  221.             new = (struct dirsort *) malloc(sizeof(struct dirsort));
  222.             if(new == NULLSORT)
  223.                 malloc_lost = TRUE;
  224.             de  = (struct dirent *)malloc(sizeof(struct dirent));
  225.             if(de == NULLENT)
  226.                 malloc_lost = TRUE;
  227.             if(malloc_lost){
  228.                 /* Clean up and call other routine */
  229.                 if(new)free(new);
  230.                 free_clist(head);
  231.                 return getdir_nosort(path,full,file);
  232.             }
  233.             *de = sbuf;    /* Copy contents of directory entry struct */
  234.  
  235.             /* Fix up names for easier sorting... pain! */
  236.             strcpy(de->fname,"           ");    /* 11 blanks */
  237.             cp  = sbuf.fname;
  238.             cp1 = de->fname;
  239.  
  240.             do *cp1++ = *cp++; while (*cp && *cp != '.');
  241.  
  242.             if(*cp++){
  243.                 /* If there is an extension */
  244.                 cp1 = &(de->fname[8]);
  245.                 do *cp1++ = *cp++; while (*cp);
  246.             }
  247.             if(!(int)head){
  248.                 /* Make the first one */
  249.                 here = head = new;
  250.                 head->prev = head->next = NULLSORT;
  251.             } else {
  252.                 /* Link on next one */
  253.                 new->next = NULLSORT;
  254.                 new->prev = here;
  255.                 here->next = new;
  256.                 here = new;
  257.             }
  258.             new->direntry = de;
  259.         } /* IF on "." */
  260.     } /* infinite FOR loop */
  261.  
  262.     if(head)
  263.         dir_sort(head);     /* Make a nice, sorted list */
  264.  
  265.     here = head;
  266.     if(here)
  267.         if(full > 0){
  268.         do {
  269.             format_dir(line_buf,here->direntry);
  270.             fprintf(file,"%s%s",line_buf,(i^=1) ? "   " : "\n");
  271.         } while (here = here->next);
  272.         if(i & 1)
  273.             fprintf(file,"\n");
  274.         }
  275.         else {
  276.         /* This is the short form */
  277.         do {
  278.             format_fname(dirtmp,here->direntry->fname,
  279.                         here->direntry->attr);
  280.             fprintf(file,"%-15s%s",dirtmp,((full && ++i % 5)?"":"\n"));
  281.         } while (here = here->next);
  282.         if(full && i % 5)
  283.             fprintf(file,"\n");
  284.         }
  285.  
  286.     /* Give back all the memory we temporarily needed... */
  287.     free_clist(head);
  288.  
  289.     if(full > 0){
  290.         /* Provide additional information only on DIR */
  291.  
  292.         if (isalpha(*path) && path[1] == ':')    /* detect A: drivespec */
  293.             diskfree(file,*path & 0x1f,n);
  294.         else
  295.             diskfree(file,0,n);
  296.     }
  297.     if(cflag)
  298.         free(path);
  299.     return 0;
  300. }
  301.  
  302. static
  303. getdir_nosort(path,full,file)
  304. char *path;
  305. int full;
  306. FILE *file;
  307. {
  308.     struct dirent sbuf;
  309.     struct stat statbuf;
  310.     register char *cp;
  311.     char dirtmp[20];
  312.     int command = FIND_FIRST;
  313.     int i = 0;
  314.     int cflag = 0;
  315.  
  316.     char    line_buf[50];        /* for long dirlist */
  317.     
  318.     void format_fname(),format_dir(),diskfree();
  319.     int n = 0;    /* Number of directory entries */
  320.     
  321.     /* Root directory is a special case */
  322.     if(path == NULLCHAR || *path == '\0' || strcmp(path,"\\") == 0)
  323.         path = "\\*.*";
  324.  
  325.     /* If arg is a directory, append "\*.*" to it.
  326.      * This is tricky, since the "stat" system call actually
  327.      * calls the DOS "find matching file" function. The stat
  328.      * call therefore returns the attributes for the first matching
  329.      * entry in the directory. If the arg already ends in *.*,
  330.      * stat will match the . entry in the directory and indicate
  331.      * that the argument is a valid directory name. Hence the
  332.      * heuristic check for '*' in the file name. Kludge...
  333.      */
  334.     else if(index(path,'*') == NULLCHAR
  335.      && stat(path,&statbuf) != -1
  336.      && (statbuf.st_attr & ST_DIRECT)) {
  337.         if((cp = malloc(strlen(path) + 10)) == NULLCHAR)
  338.             return -1;
  339.         sprintf(cp,"%s%c%s",path,'\\',"*.*");
  340.         path = cp;
  341.         cflag = 1;
  342.     }
  343.     for(;;){
  344.         bdos(SET_DTA,&sbuf);    /* Set disk transfer addre